/* 建造者模式(Builder)是将一个复杂的对象的构造和表示进行分离，使同样的构造过程可以创建不同的表示
    建造者模式可以分为4个角色：
    产品(Product):包含多个组成部件的复杂对象；
    抽象建造者(Builder): 包含创建产品各个子部件的抽象方法接口;
    具体建造者(Concrete builder): 对抽象建造者进行实现；
    指挥者(director)： 调用建造者对象的部件构造和组装完成复杂对象的创建
    
本例以肺结节检测为例，对同类论文的不同算法实现进行封装。其中肺结节检测pipeline为产品，每个步骤为部件，
步骤分为图像预处理、肺叶区域分割和肺结节检测。具体建造者为不同论文（本例中实现了两篇论文，论文Wang 和论文Li）

 */

#include <iostream>

using namespace std;


#pragma region // 抽象类模块

class Preprocessing
{
    public:
    virtual void print_name()=0;
    virtual ~Preprocessing(){};
};

class Segment
{
    public:
    virtual void print_name()=0;
    virtual ~Segment(){};
};

class Detection
{
    public:
    virtual void print_name()=0;
    virtual ~Detection(){};
};

class LesionDetection
{
    public:
    virtual void set_preprocessing(Preprocessing* preprocessing) = 0;
    virtual void set_segment(Segment* segment)=0;
    virtual void set_detection(Detection* detection)=0;
    virtual void get_report()=0;
    virtual ~LesionDetection(){};
};

class Builder
{
    public:
    virtual ~Builder(){};
    virtual void build_preprocessing()=0;
    virtual void build_segment()=0;
    virtual void build_detection()=0;
    virtual LesionDetection* get_alg()=0;
};

#pragma endregion

#pragma region // 肺结节检测

class Nodule: public LesionDetection
{
    public:
    Nodule():m_preprocessing(nullptr),m_detection(nullptr),m_segment(nullptr){}

    void set_preprocessing(Preprocessing* preprocessing){
        m_preprocessing = preprocessing;
    }

    void set_segment(Segment* segment){
        m_segment = segment;
    }

    void set_detection(Detection* detection){
        m_detection = detection;
    }

    void get_report(){
        cout<<"The pipeline of nodule including:"<<endl;
        if(m_preprocessing){
            m_preprocessing->print_name();
        }
        if(m_segment){
            m_segment->print_name();
        }
        if(m_detection){
            m_detection->print_name();
        }
    }

    ~Nodule(){
        if(m_preprocessing){
            delete m_preprocessing;
        }
        if(m_segment){
            delete m_segment;
        }
        if(m_detection){
            delete m_detection;
        }
    }

    private:
    Preprocessing* m_preprocessing;
    Segment* m_segment;
    Detection* m_detection;

};

#pragma endregion

#pragma region // 论文 wang 的实现(具体建造者)

class MiddlePreprocessing: public Preprocessing
{
    void print_name()
    {
        cout<<"Using middle filter to Preprocessing."<<endl;
    }
};

 class ThresholdSegment: public Segment
 {
    void print_name()
    {
        cout<<"Using Threshold to Segment."<<endl;
    }
};

class SiftDetection: public Detection
{
    void print_name()
    {
        cout<<"Using sift to Detection."<<endl;
    }
};

class PaperWang :public Builder
{
    public:
    PaperWang(){
        m_nodule = new Nodule();
    }
    void build_preprocessing(){
        m_nodule->set_preprocessing(new MiddlePreprocessing());
    }

    void build_segment(){
        m_nodule->set_segment(new ThresholdSegment());
    }

    void build_detection(){
        m_nodule->set_detection(new SiftDetection());
    }
    LesionDetection* get_alg(){
        return m_nodule;
    }
    private:
    Nodule* m_nodule;

};

#pragma endregion

#pragma region // 论文 li 的实现(具体建造者)

class MeanPreprocessing:public Preprocessing
{
    void print_name()
    {
        cout<<"Using mean filter to Preprocessing."<<endl;
    }
};

class GrowingSegment: public Segment
{
    void print_name()
    {
        cout<<"Using Growing to Segment"<<endl;
    }
};

class BoostDetection: public Detection
{
    void print_name()
    {
        cout <<"Using Boost to Detection."<<endl;
    }
};

class PaperLi: public Builder
{
    public:
    PaperLi(){
        m_nodule = new Nodule();
    }
    
    void build_preprocessing(){
        m_nodule->set_preprocessing(new MeanPreprocessing());
    }

    void build_segment(){
        m_nodule->set_segment(new GrowingSegment());
    }

    void build_detection(){
        m_nodule->set_detection(new BoostDetection());
    }
    
    LesionDetection* get_alg(){
        return m_nodule;
    }
    private:
    Nodule* m_nodule;
};

#pragma endregion

#pragma region // 指挥者
class Director
{
    public:
    Director(Builder* builder): m_builder(builder){}

    LesionDetection* construct(){
        m_builder->build_preprocessing();
        m_builder->build_segment();
        m_builder->build_detection();

        return m_builder->get_alg();
    }

    private:
    Builder* m_builder;
};

#pragma endregion

int main(int argc, char const *argv[])
{
    // 实际应用中，只需要修改这行代码，就可以切换不同的论文(具体建造者)实现.
    Builder* builder = new PaperWang();

    Director* director = new Director(builder);
    LesionDetection* lesion = director->construct();
    lesion->get_report();

    delete builder;
    delete director;
    
    cout<<"\n\nChange paper..."<<endl;

    builder = new PaperLi();

    director = new Director(builder);
    lesion = director->construct();
    lesion->get_report();
    
    delete builder;
    delete director;
    delete lesion;

    return 0;
}
